using System;
using System.Collections.Generic;
using System.Windows;
namespace Microsoft.Expression.Drawing.Core
{
	internal class PolylineData
	{
		private IList<Point> points;
		private IList<Vector> normals;
		private IList<double> angles;
		private IList<double> lengths;
		private IList<double> accumulates;
		private double? totalLength;
		public bool IsClosed
		{
			get
			{
				return this.points.get_Item(0) == this.points.Last<Point>();
			}
		}
		public int Count
		{
			get
			{
				return this.points.get_Count();
			}
		}
		public double TotalLength
		{
			get
			{
				double? num = this.totalLength;
				if (!num.get_HasValue())
				{
					return this.ComputeTotalLength();
				}
				return num.GetValueOrDefault();
			}
		}
		public IList<Point> Points
		{
			get
			{
				return this.points;
			}
		}
		public IList<double> Lengths
		{
			get
			{
				return this.lengths ?? this.ComputeLengths();
			}
		}
		public IList<Vector> Normals
		{
			get
			{
				return this.normals ?? this.ComputeNormals();
			}
		}
		public IList<double> Angles
		{
			get
			{
				return this.angles ?? this.ComputeAngles();
			}
		}
		public IList<double> AccumulatedLength
		{
			get
			{
				return this.accumulates ?? this.ComputeAccumulatedLength();
			}
		}
		public PolylineData(IList<Point> points)
		{
			if (points == null)
			{
				throw new ArgumentNullException("points");
			}
			if (points.get_Count() <= 1)
			{
				throw new ArgumentOutOfRangeException("points");
			}
			this.points = points;
		}
		public Vector Difference(int index)
		{
			int num = (index + 1) % this.Count;
			return this.points.get_Item(num).Subtract(this.points.get_Item(index));
		}
		public Vector SmoothNormal(int index, double fraction, double cornerRadius)
		{
			if (cornerRadius > 0.0)
			{
				double num = this.Lengths.get_Item(index);
				if (MathHelper.IsVerySmall(num))
				{
					int num2 = index - 1;
					if (num2 < 0 && this.IsClosed)
					{
						num2 = this.Count - 1;
					}
					int num3 = index + 1;
					if (this.IsClosed && num3 >= this.Count - 1)
					{
						num3 = 0;
					}
					if (num2 >= 0 && num3 < this.Count)
					{
						return GeometryHelper.Lerp(this.Normals.get_Item(num3), this.Normals.get_Item(num2), 0.5).Normalized();
					}
					return this.Normals.get_Item(index);
				}
				else
				{
					double num4 = Math.Min(cornerRadius / num, 0.5);
					if (fraction <= num4)
					{
						int num5 = index - 1;
						if (this.IsClosed && num5 == -1)
						{
							num5 = this.Count - 1;
						}
						if (num5 >= 0)
						{
							double alpha = (num4 - fraction) / (2.0 * num4);
							return GeometryHelper.Lerp(this.Normals.get_Item(index), this.Normals.get_Item(num5), alpha).Normalized();
						}
					}
					else
					{
						if (fraction >= 1.0 - num4)
						{
							int num6 = index + 1;
							if (this.IsClosed && num6 >= this.Count - 1)
							{
								num6 = 0;
							}
							if (num6 < this.Count)
							{
								double alpha2 = (fraction + num4 - 1.0) / (2.0 * num4);
								return GeometryHelper.Lerp(this.Normals.get_Item(index), this.Normals.get_Item(num6), alpha2).Normalized();
							}
						}
					}
				}
			}
			return this.Normals.get_Item(index);
		}
		private IList<double> ComputeLengths()
		{
			this.lengths = new double[this.Count];
			for (int i = 0; i < this.Count; i++)
			{
				this.lengths.set_Item(i, this.Difference(i).Length);
			}
			return this.lengths;
		}
		private IList<Vector> ComputeNormals()
		{
			this.normals = new Vector[this.points.get_Count()];
			for (int i = 0; i < this.Count - 1; i++)
			{
				this.normals.set_Item(i, GeometryHelper.Normal(this.points.get_Item(i), this.points.get_Item(i + 1)));
			}
			this.normals.set_Item(this.Count - 1, this.normals.get_Item(this.Count - 2));
			return this.normals;
		}
		private IList<double> ComputeAngles()
		{
			this.angles = new double[this.Count];
			for (int i = 1; i < this.Count - 1; i++)
			{
				this.angles.set_Item(i, -GeometryHelper.Dot(this.Normals.get_Item(i - 1), this.Normals.get_Item(i)));
			}
			if (this.IsClosed)
			{
				double num = -GeometryHelper.Dot(this.Normals.get_Item(0), this.Normals.get_Item(this.Count - 2));
				IList<double> arg_9C_0 = this.angles;
				int arg_9C_1 = 0;
				double num2;
				this.angles.set_Item(this.Count - 1, num2 = num);
				arg_9C_0.set_Item(arg_9C_1, num2);
			}
			else
			{
				IList<double> arg_C9_0 = this.angles;
				int arg_C9_1 = 0;
				double num3;
				this.angles.set_Item(this.Count - 1, num3 = 1.0);
				arg_C9_0.set_Item(arg_C9_1, num3);
			}
			return this.angles;
		}
		private IList<double> ComputeAccumulatedLength()
		{
			this.accumulates = new double[this.Count];
			this.accumulates.set_Item(0, 0.0);
			for (int i = 1; i < this.Count; i++)
			{
				this.accumulates.set_Item(i, this.accumulates.get_Item(i - 1) + this.Lengths.get_Item(i - 1));
			}
			this.totalLength = new double?(this.accumulates.Last<double>());
			return this.accumulates;
		}
		private double ComputeTotalLength()
		{
			this.ComputeAccumulatedLength();
			return this.totalLength.get_Value();
		}
	}
}
